///************************************************************************
/// <copyrigth>2018-2019 Corporation.All Rights Reserved</copyrigth>
/// <author>tangyingzhong</author>
/// <contact>tangyz114987@outlook.com</contact>
/// <version>v1.0.0</version>
/// <describe>
/// Plugin base has some funstions that plugin who inherits it can own ,too
///</describe>
/// <date>2019/9/22</date>
///***********************************************************************
#ifndef PLUGINBASE_H
#define PLUGINBASE_H

#include <string>
#include <mutex>
#include "Tool/EventHandler/EventHandler.h"
#include "Base/IPlugin.h"

#define BASE_EVENT_ID WM_USER+1

struct PluginInfo
{
	// Plugin name
	std::string strPluginName;

	// Plugin major version
	int iMajorVersion;

	// Plugin minor version
	int iMinorVersion;

	// Plugin modify version
	int iModifyVersion;

	// Is started on load
	bool bIsStartOnLoad;

	// Is main service
	bool bIsMainService;
};

template<class T1=IPlugin, class T2 = EventArgs>
class PluginBase :public T1
{
public:
	typedef IEventHandler::HandlerFunc HandlerFunc;

public:
	// Construct the plugin base
	PluginBase() :m_bIsRunning(false),m_bDisposed(false){ }

protected:
	// Destruct the plugin base
	virtual ~PluginBase()
	{
		if (!GetDisposed())
		{
			SetDisposed(true);
		}
	}

public:
	// Is plugin running
	virtual bool IsRunning()
	{
		return GetIsRunning();
	}

	// Is main service
	virtual bool IsMainService()
	{
		return m_PluginInfo.bIsMainService;
	}

	// Is started on load
	virtual bool IsStartOnLoad()
	{
		return m_PluginInfo.bIsStartOnLoad;
	}

	// Get plugin name
	virtual std::string GetName()
	{
		return GetAddinName();
	}

	// Set plugin name
	virtual bool SetName(std::string strName)
	{
		if (strName.empty())
		{
			return false;
		}

		SetAddinName(strName);

		return true;
	}

	// Set plugin version
	virtual bool SetVersion(int iMajorVersion,
		int iMinorVersion,
		int iModifyVersion)
	{
		if (iMajorVersion == 0
			&& iMinorVersion == 0
			&& iModifyVersion == 0)
		{
			return false;
		}

		SetMajorVersion(iMajorVersion);

		SetMinorVersion(iMinorVersion);

		SetModifyVersion(iModifyVersion);

		return true;
	}

	// Get plugin version
	virtual bool GetVersion(int& iMajorVersion,
		int& iMinorVersion,
		int& iModifyVersion)
	{
		if (GetMajorVersion() == 0
			&& GetMinorVersion() == 0
			&& GetModifyVersion() == 0)
		{
			return false;
		}

		iMajorVersion = GetMajorVersion();

		iMinorVersion = GetMinorVersion();

		iModifyVersion = GetModifyVersion();

		return true;
	}

	// Check plugin's compatility
	virtual bool CheckCompatible(int iMajorVersion,
		int iMinorVersion,
		int iModifyVersion)
	{
		if (iMajorVersion < GetMajorVersion())  // 2
		{
			return false;
		}

		if (iMajorVersion == GetMajorVersion())
		{
			if (iMinorVersion < GetMinorVersion()) // 5
			{
				return false;
			}

			if (iMinorVersion == GetMinorVersion())
			{
				if (iModifyVersion < GetModifyVersion())  // 1
				{
					return false;
				}

				return true;
			}

			return true;
		}
		
		return true;
	}

	// Listen plugins
	virtual void Listen(void* pListener,
		HandlerFunc pListenHandler,
		int iEventID)
	{
		m_EventHandler.RegisterEvent(pListener, iEventID, pListenHandler);
	}

protected:
	// Notidy all listeners who listening this event id
	void Notify(void* pNotifier, int iEventID, T2* pArgs)
	{
		m_EventHandler.FireEvent(pNotifier, iEventID, pArgs);
	}

	// Set the service info table
	inline void SetPluginInfo(PluginInfo Info)
	{
		m_PluginInfo = Info;
	}

	// Get is running
	inline bool GetIsRunning()
	{
		std::lock_guard<std::mutex> Locker(m_RunLock);

		return m_bIsRunning;
	}

	// Set is running
	inline void SetIsRunning(bool bIsRunning)
	{
		std::lock_guard<std::mutex> Locker(m_RunLock);

		m_bIsRunning = bIsRunning;
	}

private:
	// Get the Name
	inline std::string GetAddinName() const
	{
		return m_PluginInfo.strPluginName;
	}

	// Set the Name
	inline void SetAddinName(std::string strName)
	{
		m_PluginInfo.strPluginName = strName;
	}

	// Get the MajorVersion
	inline int GetMajorVersion() const
	{
		return m_PluginInfo.iMajorVersion;
	}

	// Set the MajorVersion
	inline void SetMajorVersion(int iMajorVersion)
	{
		m_PluginInfo.iMajorVersion = iMajorVersion;
	}

	// Get the MinorVersion
	inline int GetMinorVersion() const
	{
		return m_PluginInfo.iMinorVersion;
	}

	// Set the MinorVersion
	inline void SetMinorVersion(int iMinorVersion)
	{
		m_PluginInfo.iMinorVersion = iMinorVersion;
	}

	// Get the ModifyVersion
	inline int GetModifyVersion() const
	{
		return m_PluginInfo.iModifyVersion;
	}

	// Set the ModifyVersion
	inline void SetModifyVersion(int iModifyVersion)
	{
		m_PluginInfo.iModifyVersion = iModifyVersion;
	}

	// Get the Disposed
	inline bool GetDisposed() const
	{
		return m_bDisposed;
	}

	// Set the Disposed
	inline void SetDisposed(bool bDisposed)
	{
		m_bDisposed = bDisposed;
	}

private:
	// Service information table
	PluginInfo m_PluginInfo;

	// Event handler container
	EventHandler m_EventHandler;

	// Lock for the running
	std::mutex m_RunLock;

	// Is running
	bool m_bIsRunning;

	// Disposed state
	bool m_bDisposed;
};

#endif // PLUGINBASE_H